package com.ruoyi.common.core.utils;
 
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

 
public class JwtHelper {
	
	/**
	 * token加密时使用的密钥
	 * 一旦得到该密钥也就可以伪造token了
	 */
    private static final String key="scott";
    private static final SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;//加密方式

    //ttMillis是token持续时间
    public static String createToken(String appKey, long ttlMillis) {
        // 生成签名的时候使用的秘钥secret，切记这个秘钥不能外露哦。它就是你服务端的私钥，在任何场景都不应该流露出去。
        // 一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
        SecretKey key = generalKey();

        // 创建payload的私有声明（根据特定的业务需要添加，如果要拿这个做验证，一般是需要和jwt的接收方提前沟通好验证方式的）
        Map<String, Object> claims = new HashMap<>();
        //例如claims.put("userCode", usercode);

        String jwt_id = UUID.randomUUID().toString();

        // 设置JWT的签发时间和过期时间
        Date now = new Date();
        Date expiration = new Date(now.getTime() + ttlMillis);
        // 使用指定的密钥和算法生成JWT
        return Jwts.builder()
                .setClaims(claims)
                .setId(jwt_id)	// 设置jti(JWT ID)：是JWT的唯一标识，根据业务需要，这个可以设置为一个不重复的值，主要用来作为一次性token,从而回避重放攻击。
                .setSubject(appKey)	//设置token拥有者
                .setIssuedAt(now)	// 设置签发时间
                .setExpiration(expiration) // 设置过期时间
                .signWith(signatureAlgorithm,key) // 设置签名密钥和签名算法
                .compact(); // 生成JWT字符串
    }

    //验证token如果正确返回用户id
    public static R checkToken(String token){
        SecretKey key = generalKey();  //签名秘钥，和生成的签名的秘钥一模一样
        try {
            // 解析token
            Claims claims = Jwts.parser()
                    .setSigningKey(key) // 设置密钥
                    .parseClaimsJws(token) // 解析token
                    .getBody(); // 获取负载

            // 验证负载中的信息
            String subject = claims.getSubject(); // 获取用户ID或其他信息
            Date expiration = claims.getExpiration(); // 获取过期时间
            System.out.println(expiration.toString());

            // 验证token是否过期
            if (expiration.before(new Date())) {
                throw new TokenException("token失效");
            }
            return R.success(subject);

        } catch (ExpiredJwtException e) {
            // 当token过期时，会捕获到ExpiredJwtException异常
            return R.error("Token已过期");
        } catch (UnsupportedJwtException e) {
            // 当token不受支持时，会捕获到UnsupportedJwtException异常
            return R.error("Token不受支持");
        } catch (MalformedJwtException e) {
            // 当token格式错误时，会捕获到MalformedJwtException异常
            return R.error("Token格式错误");
        } catch (SignatureException e) {
            // 当token签名错误时，会捕获到SignatureException异常
            return R.error("Token签名错误");
        } catch (IllegalArgumentException e) {
            // 当token为空或非法时，会捕获到IllegalArgumentException异常
            return R.error("Token为空或非法");
        } catch (TokenException e) {
            // 处理TokenException
            return R.error("Token验证失败: " + e.getMessage());
        } catch (Exception e) {
            // 处理其他异常
            return R.error("发生未知错误: " + e.getMessage());
        }
    }


    /**
     * 由字符串生成加密key
     *
     * @return
     */
    private static SecretKey generalKey() {
        // 本地的密码解码
        byte[] encodedKey = Base64.decodeBase64(key);
        // 根据给定的字节数组使用AES加密算法构造一个密钥
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }














    // 解析JWT获取appKey的方法
    public static String parseAppKeyFromToken(String token) {
        try {
            // 获取密钥
            SecretKey key = generalKey();

            // 解析JWT
            Claims claims = Jwts.parser()
                    .setSigningKey(key)
                    .parseClaimsJws(token)
                    .getBody();

            // 获取subject，即appKey
            return claims.getSubject();

        } catch (Exception e) {
            // 处理各种可能的异常（过期、签名无效等）
            System.err.println("Token解析失败: " + e.getMessage());
            return null;
        }
    }

    // 测试验证
/*    public static void main(String[] args) {
        // 创建测试token
        String appKey = "test_app_key_123";
        long ttlMillis = 3600000; // 1小时
        String token = createToken(appKey, 1000 * 60 * 60);

        System.out.println("生成的Token: " + token);

        // 解析token获取appKey
        String parsedAppKey = parseAppKeyFromToken(token);

        System.out.println("解析出的AppKey: " + parsedAppKey);
        System.out.println("是否匹配: " + appKey.equals(parsedAppKey));
    }*/

}
